#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/errno.h>

int **table;
int rows = 4;
int columns = 4;
int *subtotal;

/*
* we define a structure that contains one property
*/
struct arguments {
	int argument;
};

/*
* Function that will be executed on a background thread
*/
void* sum_row(void *parametr_argumenty)
{
	struct arguments * nowe_argumenty = parametr_argumenty;
	
	int i;
	
	printf("[Auxiliary thread] Mam tid %u.\n", (unsigned int)pthread_self());
	
	printf("[Auxiliary thread nr %d] Doing sum of row nbr: %d.\n", 
		nowe_argumenty->argument,  
		nowe_argumenty->argument);
	
	for(i=0; i<columns; i++)
	{
		subtotal[nowe_argumenty->argument] += table[nowe_argumenty->argument][i];
	}
	
	printf("[Child Thread %d] The sum is: %d.\n", nowe_argumenty->argument, subtotal[nowe_argumenty->argument]);
	
	pthread_exit(0);
}

/**
* This function print a message to the stdout and exit the program (thus terminating all threads)
*
*/
void showErrorAndTerminate(char tekst[])
{
	printf("ERROR : %s !!!",tekst);
	exit(-1);
}


/**
* Main function
*/
int main()
{
	printf("[Main thread] tid %d.\n", (unsigned int)pthread_self());

	int i;
	//-------------------------------------------------
	//1. Allocate memory to pointer variables
	//-------------------------------------------------
	pthread_t *id_thread;
	id_thread = (pthread_t *) malloc(sizeof(pthread_t *) * rows);	
	subtotal = (int *) malloc(sizeof(int *) * rows);

	//-------------------------------------------------	
	//2. Initialize the subtotal of each row
	//-------------------------------------------------
	for(i=0; i<rows; i++)
	{
		subtotal[i] = 0;
	}

	//-------------------------------------------------
	//3. Allocate memory to pointer to pointer to int variable
	//-------------------------------------------------
	table = (int **) malloc(sizeof(int **) * rows);
	
	for(i=0; i<rows; i++)
	{
		//each row of the table is an array of int actually...
		table[i] = (int *) malloc(sizeof(int *) * columns);
	}
	
	//-------------------------------------------------
	//4. We put data into the table
	//-------------------------------------------------
	printf("[Main thread] we put data into the table.\n");
	
	int r,c;	
	// We set the seed for a new sequence of  pseudo-random
	srand(time(NULL));	
	for(r=0; r<rows; r++)
	{
		for(c=0; c<columns; c++)
		{
			table[r][c] = rand() % 10; //we put a random number
		}
	}

	//-------------------------------------------------
	//5. We print the table (just for verification)
	//-------------------------------------------------
	
	printf("[Main thread] print the table.\n");
	
	for(r=0; r<rows; r++)
	{
		for(c=0; c<columns; c++)
		{
			printf("\t%d", table[r][c]);
		}
		printf("\n");
	}


	//-------------------------------------------------
	//6. We prepare to create several threads: sum_row is the function that starts the threads
	//-------------------------------------------------
	
	int row_id;
	
	struct arguments *nowe_argumenty;
	
	nowe_argumenty = (struct arguments *) malloc(sizeof(struct arguments *) * rows);
	
	for(row_id=0; row_id <rows; row_id++)
	{
		nowe_argumenty[row_id].argument = row_id;
		
		printf("[System] Create a thread nr %d.\n", row_id);
		
		if (pthread_create(&id_thread[row_id], NULL, &sum_row, (void *) &nowe_argumenty[row_id]) != 0)
		{
			showErrorAndTerminate("PORAŻKA!\n");
		}
		
	}
	
	//-------------------------------------------------
	//7. We join the thread: we wait for the thread to terminate (to avoid "zombie" threads)
	//-------------------------------------------------
	
	for(row_id=0; row_id<rows; row_id++)
	{
		printf("[System] Joining thread tid-zie %u.\n", (unsigned int)id_thread[row_id]);
		if (pthread_join(id_thread[row_id], NULL) != 0)
		{
			showErrorAndTerminate("PORAŻKA!\n");
		}
	}	
	
	
	//-------------------------------------------------
	//8. We display the overall total (computer by indepedent threads)
	//-------------------------------------------------
	
	int overall_total = 0;
	
	for(row_id=0; row_id<rows; row_id++)
	{
		printf("[Main Thread] We add up the subtotals.\n");
		overall_total += subtotal[row_id];
	}
	
	printf("[Main Thread] The overal Total: %d.\n", overall_total);
	
	return 0;
}
//main
